/**
 * Copyright (C) 2021 - 2031 O-Cubes Co., Ltd.
 */

/****************************************************************
 *  @file    system.c
 *  @brief   EOC Device System Init
 *  @version v1.0
 *  @date    03. Apr. 2023
 ****************************************************************/
#include <string.h>
#include <stdlib.h>

#include "core.h"
#include "irq.h"
#include "bits.h"
#include "config_p1.h"

//unsigned long Addr1[8];
/**
 *  The ranges of copy from/to are specified by following symbols
 *    __erodata: LMA of start of the section to copy from. Usually end of rodata
 *    __data_start__: VMA of start of the section to copy to
 *    __data_end__: VMA of end of the section to copy to
 *
 *  All addresses must be aligned to 4 bytes boundary.
 */
static void section_data_copy(void)
{
	extern unsigned long __erodata;
	extern unsigned long __data_start__;
	extern unsigned long __data_end__;

	if (((unsigned long)&__erodata != (unsigned long)&__data_start__)) {
		unsigned long src_addr = (unsigned long)&__erodata;
		memcpy((void *)(&__data_start__), \
			(void *)src_addr, \
			(unsigned long)(&__data_end__) - (unsigned long)(&__data_start__));
	}
}

static void section_ram_code_copy(void)
{
	extern unsigned long __erodata;
	extern unsigned long __data_start__;
	extern unsigned long __data_end__;
	extern unsigned long __ram_code_start__;
	extern unsigned long __ram_code_end__;
	
	if (((unsigned long)&__erodata != (unsigned long)&__data_start__)) {
		unsigned long src_addr = (unsigned long)&__erodata;
		src_addr += (unsigned long)(&__data_end__) - (unsigned long)(&__data_start__);
		memcpy((void *)(&__ram_code_start__), \
			(void *)src_addr, \
			(unsigned long)(&__ram_code_end__) - (unsigned long)(&__ram_code_start__));
	}
}

/**
 *  The BSS section is specified by following symbols
 *    __bss_start__: start of the BSS section.
 *    __bss_end__: end of the BSS section.
 *
 *  Both addresses must be aligned to 4 bytes boundary.
 */
static void section_bss_clear(void)
{
	extern unsigned long __bss_start__;
	extern unsigned long __bss_end__;

	memset((void *)(&__bss_start__), \
		0, \
		(unsigned long)(&__bss_end__) - (unsigned long)(&__bss_start__));
}

/**
 * Enable T-HEAD extended instructions
 */
void enable_thead_isaee(void)
{
	uint32_t mxstatus = __get_MXSTATUS();

	mxstatus |= BIT(22);
	__set_MXSTATUS(mxstatus);
}

static void cache_init(void)
{
	/* only open icache and dcache */
	uint32_t cache = 0x103F;

	__DSB();
	__ISB();

	__set_MHCR(cache);

	__DSB();
	__ISB();
}

static void irq_unmask_all(void)
{
	uint32_t mstatus = __get_MSTATUS();

	mstatus |= BIT(3);

	__DSB();
	__ISB();

	__set_MSTATUS(mstatus);

	__DSB();
	__ISB();
}

static void irq_mask_all(void)
{
	uint32_t mstatus = __get_MSTATUS();

	mstatus &= ~(BIT(3));

	__DSB();
	__ISB();

	__set_MSTATUS(mstatus);

	__DSB();
	__ISB();
}

static void section_init(void)
{
	section_data_copy();
#ifdef SPIFLASH_XIP_EN
	section_ram_code_copy();
#endif
	section_bss_clear();
}

static void clic_init(void)
{
	int i;

	//CLIC->CLICCFG = 0x4UL;

	/* Get interrupt level from info */
	CLIC->CLICCFG |= (((CLIC->CLICINFO & CLIC_INFO_CLICINTCTLBITS_Msk) >> CLIC_INFO_CLICINTCTLBITS_Pos) << CLIC_CLICCFG_NLBIT_Pos);

	for (i = RTC_IRQn; i < MAXIMUM_CLIC_IRQn; i++) {
		CLIC->CLICINT[i].IE = 0;
		CLIC->CLICINT[i].IP = 0;
		CLIC->CLICINT[i].ATTR |= 0x01; /* use vector interrupt */
	}

	/* tspend use positive interrupt */
	CLIC->CLICINT[Machine_Software_IRQn].ATTR |= 0x01;
	irq_enable(Machine_Software_IRQn);

	CLIC->CLICINT[Machine_Timer_IRQn].ATTR |= 0x01;
}

void SystemInit(void)
{
	//extern unsigned long __erodata;
	//extern unsigned long __data_start__;
	//extern unsigned long __data_end__;
	//extern unsigned long __ram_code_start__;
	//extern unsigned long __ram_code_end__;
	//extern unsigned long __bss_start__;
	//extern unsigned long __bss_end__;
	
	enable_thead_isaee();

	cache_init();

	section_init();

	clic_init();

	irq_unmask_all();
	
	//Addr1[0] = __erodata;
	//Addr1[1] = __data_start__;
	//Addr1[2] = __data_end__;
	//Addr1[3] = __ram_code_start__;
	//Addr1[4] = __ram_code_end__;
	//Addr1[5] = __bss_start__;
	//Addr1[6] = __bss_end__;
}

